home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / hidden3d.c < prev    next >
C/C++ Source or Header  |  1996-01-22  |  19KB  |  556 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: hidden3d.c,v 1.6 1995/12/02 22:04:34 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - hidden3d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *
  20.  * This software is provided "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *       Gershon Elber and many others.
  27.  *
  28.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  29.  * Added user-specified bases for log scaling.
  30.  *
  31.  * 3.6 - split graph3d.c into graph3d.c (graph),
  32.  *                            util3d.c (intersections, etc)
  33.  *                            hidden3d.c (hidden-line removal code)
  34.  *
  35.  * There is a mailing list for gnuplot users. Note, however, that the
  36.  * newsgroup 
  37.  *    comp.graphics.gnuplot 
  38.  * is identical to the mailing list (they
  39.  * both carry the same set of messages). We prefer that you read the
  40.  * messages through that newsgroup, to subscribing to the mailing list.
  41.  * (If you can read that newsgroup, and are already on the mailing list,
  42.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  43.  * removed from the mailing list.)
  44.  *
  45.  * The address for mailing to list members is
  46.  *       info-gnuplot@dartmouth.edu
  47.  * and for mailing administrative requests is 
  48.  *       info-gnuplot-request@dartmouth.edu
  49.  * The mailing list for bug reports is 
  50.  *       bug-gnuplot@dartmouth.edu
  51.  * The list of those interested in beta-test versions is
  52.  *       info-gnuplot-beta@dartmouth.edu
  53.  */
  54.  
  55. #include <math.h>
  56. #if !defined(sequent) && !defined(apollo) && !defined(alliant)
  57. #include <limits.h>
  58. #endif
  59. #include "plot.h"
  60. #include "setshow.h"
  61.  
  62. extern int suppressMove;
  63.  
  64. extern int xright,xleft,ybot,ytop;
  65.  
  66. extern double min_array[], max_array[];
  67. extern int auto_array[], log_array[];
  68. extern double base_array[], log_base_array[];
  69.  
  70. /* for convenience while converting to use these arrays */
  71. #define x_min3d min_array[FIRST_X_AXIS]
  72. #define x_max3d max_array[FIRST_X_AXIS]
  73. #define y_min3d min_array[FIRST_Y_AXIS]
  74. #define y_max3d max_array[FIRST_Y_AXIS]
  75. #define z_min3d min_array[FIRST_Z_AXIS]
  76. #define z_max3d max_array[FIRST_Z_AXIS]
  77. #define min3d_z min_array[FIRST_Z_AXIS]
  78. #define max3d_z max_array[FIRST_Z_AXIS]
  79.  
  80. extern int base_z;
  81. extern int hidden_no_update, hidden_active;
  82. extern int hidden_line_type_above, hidden_line_type_below;
  83.  
  84. static int zsort __P((int * r1, int * r2));
  85.  
  86.  
  87. /* We divvy up the figure into the component boxes that make it up, and then
  88.    sort them by the z-value (which is really just an average value).  */
  89. struct pnts{
  90.   unsigned int x,y,z;
  91.   int flag;
  92.   long int style_used;    /* acw test */
  93.   int nplot;
  94. };
  95. static int * boxlist;
  96. static struct pnts * nodes;
  97.  
  98. /* These variables are used to keep track of the range of x values used in the
  99. line drawing routine.  */
  100.  
  101. /* THESE SHOULD BE STATIC but util3d.c needs them - try to move code
  102.  * from util3d.c into here
  103.  */
  104.  
  105. long int xmin_hl,xmax_hl;
  106. /* These arrays are used to keep track of the minimum and maximum y values used
  107.    for each X value.  These are only used for drawing the individual boxes that
  108.    make up the 3d figure.  After each box is drawn, the information is copied
  109.    to the bitmap. */
  110. short int *ymin_hl=0, *ymax_hl=0;
  111. /*
  112.  * These numbers are chosen as dividers into the bitmap.
  113.  */
  114. int xfact, yfact;
  115. #define XREDUCE(X) ((X)/xfact)
  116. #define YREDUCE(Y) ((Y)/yfact)
  117. /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
  118. unsigned short int **pnt=0;
  119. #define IFSET(X,Y) (pnt[X] == 0 ? 0 : (((pnt[X])[(Y)>>4] >> ((Y) & 0xf)) & 0x01))
  120.  
  121.  
  122. /* Initialize the necessary steps for hidden line removal. */
  123. void init_hidden_line_removal()
  124. {
  125.   int i;
  126.   /*  We want to keep the bitmap size less than 2048x2048, so we choose
  127.    *  integer dividers for the x and y coordinates to keep the x and y
  128.    *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
  129.    *  will be somewhere between 1024 and 2048, except in cases where the
  130.    *  coordinates ranges for the device are already less than 1024.
  131.    *  We do this mainly to control the size of the bitmap, but it also
  132.    *  speeds up the computation.  We maintain separate dividers for
  133.    *  x and y.
  134.    */
  135.   xfact = (xright-xleft)/1024;
  136.   yfact = (ytop-ybot)/1024;
  137.   if(xfact == 0) xfact=1;
  138.   if(yfact == 0) yfact=1;
  139.   if(pnt == 0){
  140.     i = sizeof(short int*)*(XREDUCE(xright) - XREDUCE(xleft) + 1);
  141.     pnt = (unsigned short int **) alloc((unsigned long)i, "hidden");
  142.     memset(pnt, 0, i);
  143.   };
  144.   ymin_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  145.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  146.   ymax_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  147.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  148. }
  149.  
  150. /* Reset the hidden line data to a fresh start.                     */
  151. void reset_hidden_line_removal()
  152. {
  153.     int i;
  154.     if(pnt){
  155.       for(i=0;i<=XREDUCE(xright)-XREDUCE(xleft);i++) {
  156.     if(pnt[i])
  157.       { free(pnt[i]); pnt[i] = 0;};
  158.       };
  159.     };
  160. }
  161.  
  162. /* Terminates the hidden line removal process. Free any memory allocated by  */
  163. /* init_hidden_line_removal above.                         */
  164. void term_hidden_line_removal()
  165. {
  166.      if(pnt){
  167.        int j;
  168.        for(j=0;j<=XREDUCE(xright)-XREDUCE(xleft);j++) {
  169.      if(pnt[j])
  170.        { free(pnt[j]); pnt[j] = 0;};
  171.        };
  172.        free(pnt);
  173.        pnt = 0;
  174.      };
  175.    if(ymin_hl) free(ymin_hl), ymin_hl = 0;
  176.    if(ymax_hl) free(ymax_hl), ymax_hl = 0;
  177. }
  178.  
  179.  
  180. static int zsort( r1, r2)
  181. int * r1;
  182. int * r2;
  183. {
  184.   int z1, z2;
  185.   z1 = nodes[*r1].z;
  186.   z2 = nodes[*r2].z;
  187.   if (z1 < z2) return 1;
  188.   if (z1 == z2) return 0;
  189.   return -1;
  190. }
  191. #define TESTBOX(X,Y)                    \
  192.   if(X<xmin_box) xmin_box = X;                \
  193.   if(X>xmax_box) xmax_box = X;                \
  194.   if(Y<ymin_box) ymin_box = Y;                \
  195.   if(Y>ymax_box) ymax_box = Y;
  196. /* Usefull macro to help us figure out which side of the surface we are on */
  197. #define XPRD(I,J,K)                     \
  198.   ((nodes[I].x-nodes[J].x)*(nodes[J].y-nodes[K].y) -    \
  199.   (nodes[I].y-nodes[J].y)*(nodes[J].x-nodes[K].x))
  200. #define MAYBE_LINEPOINT(J)                        \
  201.     if((nodes[J].flag & 0x20) != 0) {                \
  202.       x = nodes[J].x;                        \
  203.       y = nodes[J].y;                        \
  204.       nodes[J].flag -= 0x20;                    \
  205.       if (!clip_point(x,y) &&                     \
  206.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
  207.     (*t->point)(x,y, plot_info[nplot].point_type);        \
  208.     };
  209.  
  210. struct surface_plots{
  211.   int above_color;
  212.   int below_color;
  213.   int row_offset;
  214.   int point_type;
  215. };
  216. /* All of the plots coming into this routine are assumed to have grid
  217.    topology.  */
  218.  
  219. void plot3d_hidden(plots, pcount)
  220.      struct surface_points *plots;
  221.      int pcount;
  222. {
  223.   struct surface_points *this_plot;
  224.   long int i, j;
  225.   int nplot;
  226.   long int x,y,z ,nseg, ncrv, ncrv1;        /* point in terminal coordinates */
  227.   unsigned short int * cpnt;
  228.   short int  mask1, mask2;
  229.   long int indx1, indx2, k, m;
  230.   short int xmin_box, xmax_box, ymin_box, ymax_box;
  231.   struct surface_plots * plot_info;
  232.   int row_offset, nnode;
  233.   short int y_malloc;  /* Amount of space we need for one vertical row of
  234.                           bitmap, and byte offset of first used element */
  235.   struct termentry *t = term;
  236.   struct iso_curve *icrvs;
  237.   int current_style = 0x7fff;  /* Current line style */
  238.   int surface;
  239.   nnode = 0;
  240.   nseg = 0;
  241.   nplot = 0;
  242.   this_plot = plots;
  243.  
  244.   for (surface = 0;
  245.        surface < pcount;
  246.        this_plot = this_plot->next_sp, surface++) {
  247.     nplot++;
  248.     icrvs = plots->iso_crvs;
  249.     icrvs = plots->iso_crvs;
  250.     if(this_plot->plot_type == FUNC3D) {
  251.         ncrv=0;
  252.         for(icrvs = this_plot->iso_crvs;icrvs;icrvs=icrvs->next)
  253.             ++ncrv;
  254.     }
  255.     else if(this_plot->plot_type == DATA3D)
  256.        ncrv = this_plot->num_iso_read;
  257.     else {
  258.         graph_error("Plot type is neither function nor data");
  259.         return; /* stops a gcc -Wunitialised warning */
  260.     }
  261.     nnode += ncrv * (this_plot->iso_crvs->p_count);
  262. /*    for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  263.     nnode += ncrv * (this_plot->iso_crvs->p_count); */
  264.     switch(this_plot->plot_style) {
  265.     case YERRORBARS:
  266.     case XERRORBARS:
  267.     case XYERRORBARS:
  268.     case DOTS:
  269.     case POINTSTYLE:
  270.     case LINESPOINTS:
  271.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  272.       break;
  273.     case LINES:
  274.       nseg += (ncrv-1) * (this_plot->iso_crvs->p_count-1);
  275.       break;
  276.     case IMPULSES:
  277.       /* There will be two nodes for each segment */
  278.       nnode += ncrv * (this_plot->iso_crvs->p_count);
  279.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  280.       break;
  281.     }
  282.   };
  283.   boxlist = (int *) alloc((unsigned long)sizeof(int)*nseg, "hidden");
  284.   nodes = (struct pnts *) alloc((unsigned long)sizeof(struct pnts)*nnode, "hidden");
  285.   plot_info = (struct surface_plots *) alloc((unsigned long)sizeof(struct surface_plots)*nplot,"hidden");
  286.   nnode = 0;
  287.   nseg = 0;
  288.   nplot = 0;
  289.   this_plot = plots;
  290.   hidden_no_update = FALSE;
  291.  
  292.   if ( hidden3d && draw_surface)
  293.     for (surface = 0;
  294.      surface < pcount;
  295.      this_plot = this_plot->next_sp, surface++) {
  296.       (*t->linetype)(this_plot->line_type);
  297.       hidden_line_type_above = this_plot->line_type;
  298.         hidden_line_type_below = this_plot->line_type + 1;
  299.     if(this_plot->plot_type == FUNC3D) {
  300.       for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  301. /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  302.     };
  303.     if(this_plot->plot_type == DATA3D)
  304.       ncrv = this_plot->num_iso_read;
  305.       icrvs = this_plot->iso_crvs;
  306.       ncrv1 = ncrv;
  307.       ncrv = 0;
  308.       while ( icrvs) {
  309.     struct coordinate GPHUGE *points = icrvs->points;
  310.     for (i = 0; i < icrvs->p_count; i++) {
  311.       map3d_xy(points[i].x, points[i].y, points[i].z,&nodes[nnode].x,&nodes[nnode].y);
  312.       nodes[nnode].z = map3d_z(points[i].x, points[i].y, points[i].z);
  313.       nodes[nnode].flag = (i==0 ? 1 : 0) + (ncrv == 0 ? 2 : 0) +
  314.         (i == icrvs->p_count-1 ? 4 : 0) + (ncrv == ncrv1-1 ? 8 : 0);
  315.       nodes[nnode].nplot = nplot;
  316.       nodes[nnode].style_used = -1000; /* indicates no style */
  317.       switch(this_plot->plot_style) {
  318.       case LINESPOINTS:
  319.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  320.           nodes[nnode].flag |= 0x30;
  321.         else
  322.           nodes[nnode].flag |= 0x20;
  323.         boxlist[nseg++] = nnode++;
  324.         break;
  325.       case LINES:
  326.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  327.           {
  328.         nodes[nnode].flag |= 0x10;
  329.         boxlist[nseg++] = nnode++;
  330.           }
  331.         else
  332.           nnode++;
  333.         break;
  334.           case YERRORBARS:
  335.           case XERRORBARS:
  336.           case XYERRORBARS:
  337.       case POINTSTYLE:
  338.       case DOTS:
  339.         nodes[nnode].flag |= 0x40;
  340.         boxlist[nseg++] = nnode++;
  341.         break;
  342.       case IMPULSES:
  343.         nodes[nnode].flag |= 0x80;
  344.         boxlist[nseg++] = nnode++;
  345.         map3d_xy(points[i].x, points[i].y, (double)base_z,
  346.                      &nodes[nnode].x,&nodes[nnode].y);
  347.         nodes[nnode].z = map3d_z(points[i].x, points[i].y, (double)base_z);
  348.         nnode++;
  349.         break;
  350.       }
  351.     }
  352.     icrvs = icrvs->next;
  353.     ncrv++;
  354.     if(ncrv == ncrv1) break;
  355.       }
  356.       /* Next we go through all of the boxes, and substitute the average z value
  357.      for the box for the z value of the corner node */
  358.       plot_info[nplot].above_color = this_plot->line_type;
  359.       plot_info[nplot].below_color = this_plot->line_type+1;
  360.       plot_info[nplot].point_type =
  361.     ((this_plot->plot_style == DOTS) ? -1 : this_plot->point_type);
  362.       plot_info[nplot++].row_offset = this_plot->iso_crvs->p_count;
  363.     }
  364.       for(i=0; i<nseg; i++){
  365.     j = boxlist[i];
  366.     if ((nodes[j].flag & 0x80) != 0) {
  367.       nodes[j].z = (nodes[j].z < nodes[j+1].z ? nodes[j].z : nodes[j+1].z);
  368.       continue;
  369.     };
  370.     if ((nodes[j].flag & 0x10) == 0) continue;
  371.     row_offset = plot_info[nodes[j].nplot].row_offset;
  372.     z = nodes[j].z;
  373.     if (z < nodes[j+1].z) z = nodes[j+1].z;
  374.     if (z < nodes[j+row_offset].z) z = nodes[j+row_offset].z;
  375.     if (z < nodes[j+row_offset+1].z) z = nodes[j+row_offset+1].z;
  376.       };
  377.   qsort (boxlist, nseg, sizeof(int), (sortfunc)zsort);
  378.   y_malloc = (2+ (YREDUCE(ytop)>>4) - (YREDUCE(ybot)>>4))*sizeof(short int);
  379.   for(i=0;i<=(XREDUCE(xright)-XREDUCE(xleft));i++) {
  380.     ymin_hl[i] = 0x7fff; 
  381.     ymax_hl[i] = 0;
  382.   };
  383.   for(i=0;i<nseg;i++) {
  384.     j = boxlist[i];
  385.     nplot = nodes[j].nplot;
  386.     row_offset = plot_info[nplot].row_offset;
  387.     if((nodes[j].flag & 0x40) != 0) {
  388.       x = nodes[j].x;
  389.       y = nodes[j].y;
  390.       if (!clip_point(x,y) &&
  391.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot)))
  392.     (*t->point)(x,y, plot_info[nplot].point_type);
  393.     };
  394.     if((nodes[j].flag & 0x80) != 0) { /* impulses */
  395.       clip_move(nodes[j].x,nodes[j].y);
  396.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  397.     };
  398.     if((nodes[j].flag & 0x10) != 0) {
  399. /* It is possible, and often profitable, to take a quick look and see
  400.    if the current box is entirely obscured.  If this is the case we will
  401.    not even bother testing this box any further.  */
  402.       xmin_box = 0x7fff; 
  403.       xmax_box = 0;
  404.       ymin_box = 0x7fff; 
  405.       ymax_box = 0;
  406.       TESTBOX(nodes[j].x-xleft,nodes[j].y-ybot);
  407.       TESTBOX(nodes[j+1].x-xleft,nodes[j+1].y-ybot);
  408.       TESTBOX(nodes[j+row_offset].x-xleft,nodes[j+row_offset].y-ybot);
  409.       TESTBOX(nodes[j+row_offset+1].x-xleft,nodes[j+row_offset+1].y-ybot);
  410.       z=0;
  411.       if(xmin_box < 0) xmin_box = 0;
  412.       if(ymin_box < 0) ymin_box = 0;
  413.       if(xmax_box > xright-xleft) xmax_box = xright-xleft;
  414.       if(ymax_box > ytop-ybot) ymax_box = ytop-ybot;
  415.       /* Now check bitmap.  These coordinates have not been reduced */
  416.       if(xmin_box <= xmax_box && ymin_box <= ymax_box){
  417.     ymin_box = YREDUCE(ymin_box);
  418.     ymax_box = YREDUCE(ymax_box);
  419.     xmin_box = XREDUCE(xmin_box);
  420.     xmax_box = XREDUCE(xmax_box);
  421.     indx1 = ymin_box >> 4;
  422.     indx2 = ymax_box >> 4;
  423.     mask1 = 0xffff << (ymin_box & 0x0f);
  424.     mask2 = 0xffff >> (0x0f-(ymax_box & 0x0f));
  425.     for(m=xmin_box;m<=xmax_box;m++) {
  426.       if(pnt[m] == 0) {z++; break;};
  427.       cpnt = pnt[m] + indx1;
  428.       if(indx1 == indx2){
  429.         if((*cpnt & mask1 & mask2) != (mask1 & mask2)) {z++; break;}
  430.       } else {
  431.         if((*cpnt++ & mask1) != mask1) {z++; break;}
  432.         k = indx1+1;
  433.         while (k != indx2) {
  434.           if(*cpnt++ != 0xffff) {z++; break;}
  435.           k++;
  436.         };
  437.         if((*cpnt++ & mask2) != mask2) {z++; break;}
  438.       };
  439.     };
  440.       };
  441.       /* z is 0 if all of the pixels used by the current box are already covered.
  442.      No point in proceeding, so we just skip all further processing of this
  443.      box. */
  444.       if(!z) continue;
  445.       /* Now we need to figure out whether we are looking at the top or the
  446.      bottom of the square.  A simple cross product will tell us this.
  447.      If the square is really distorted then this will not be accurate,
  448.      but in such cases we would actually be seeing both sides at the same
  449.      time.  We choose the vertex with the largest z component to
  450.      take the cross product at.  */
  451.       {
  452.     int z1, z2 ,z3, z4;
  453.     z1 = XPRD(j+row_offset,j,j+1);
  454.     z2 = XPRD(j,j+1,j+1+row_offset);
  455.     z3 = XPRD(j+1,j+row_offset+1,j+row_offset);
  456.     z4 = XPRD(j+row_offset+1,j+row_offset,j);
  457.     z=0;
  458.     z += (z1 > 0 ? 1 : -1);
  459.     z += (z2 > 0 ? 1 : -1);
  460.     z += (z3 > 0 ? 1 : -1);
  461.     z += (z4 > 0 ? 1 : -1);
  462.     /* See if the box is uniformly one side or another. */
  463.     if(z != 4 && z != -4) {
  464. /* It isn't.  Now find the corner of the box with the largest z value that
  465.    has already been plotted, and use the same style used for that node.  */
  466.       k = -1000;
  467.       x = -32768;
  468.       if (nodes[j].z > x && nodes[j].style_used !=-1000) {
  469.         k = nodes[j].style_used;
  470.         x = nodes[j].z;
  471.       };
  472.       if (nodes[j+1].z > x && nodes[j+1].style_used !=-1000) {
  473.         k = nodes[j+1].style_used;
  474.         x = nodes[j+1].z;
  475.       };
  476.       if (nodes[j+row_offset+1].z > x && nodes[j+row_offset+1].style_used !=-1000) {
  477.         k = nodes[j+row_offset+1].style_used;
  478.         x = nodes[j+row_offset+1].z;
  479.       };
  480.       if (nodes[j+row_offset].z > x && nodes[j+row_offset].style_used !=-1000) {
  481.         k = nodes[j+row_offset].style_used;
  482.         x = nodes[j+row_offset].z;
  483.       };
  484.       if( k != -1000){
  485.         z = 0; /* To defeat the logic to come.  */
  486.         current_style = k;
  487.         (*t->linetype)(current_style);
  488.       };
  489.     };
  490.     /* If k == -1000 then no corner found.  I guess it does not matter.  */
  491.       };
  492.       if(z > 0 && current_style != plot_info[nplot].above_color) {
  493.     current_style = plot_info[nplot].above_color;
  494.     (*t->linetype)(current_style);
  495.       };
  496.       if(z < 0 && current_style != plot_info[nplot].below_color) {
  497.     current_style = plot_info[nplot].below_color;
  498.     (*t->linetype)(current_style);
  499.       };
  500.       xmin_hl = (sizeof(xleft) == 4 ? 0x7fffffff : 0x7fff ); 
  501.       xmax_hl = 0;
  502.       clip_move(nodes[j].x,nodes[j].y);
  503.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  504.       clip_vector(nodes[j+row_offset+1].x,nodes[j+row_offset+1].y);
  505.       clip_vector(nodes[j+row_offset].x,nodes[j+row_offset].y);
  506.       clip_vector(nodes[j].x,nodes[j].y);
  507.       nodes[j].style_used = current_style;
  508.       nodes[j+1].style_used = current_style;
  509.       nodes[j+row_offset+1].style_used = current_style;
  510.       nodes[j+row_offset].style_used = current_style;
  511.       MAYBE_LINEPOINT(j);
  512.       MAYBE_LINEPOINT(j+1);
  513.       MAYBE_LINEPOINT(j+row_offset+1);
  514.       MAYBE_LINEPOINT(j+row_offset);
  515.       if( xmin_hl < 0 || xmax_hl > XREDUCE(xright)-XREDUCE(xleft))
  516.     graph_error("Logic error #3 in hidden line");
  517.       /* now mark the area as being filled in the bitmap.  These coordinates
  518.          have already been reduced. */
  519.       if (xmin_hl < xmax_hl)
  520.     for(j=xmin_hl;j<=xmax_hl;j++) {
  521.       if (ymin_hl[j] == 0x7fff) 
  522.         graph_error("Logic error #2 in hidden line");
  523.       if(pnt[j] == 0) {
  524.         pnt[j] = (unsigned short int *) alloc((unsigned long)y_malloc,"hidden");
  525.         memset(pnt[j], 0, y_malloc);
  526.       };
  527.       if(ymin_hl[j] < 0 || ymax_hl[j] > YREDUCE(ytop)-YREDUCE(ybot))
  528.         graph_error("Logic error #1 in hidden line");
  529. /* this shift is wordsize dependent */
  530.       indx1 = ymin_hl[j] >> 4;
  531.       indx2 = ymax_hl[j] >> 4;
  532.       mask1 = 0xffff << (ymin_hl[j] & 0xf);
  533.       mask2 = 0xffff >> (0xf-(ymax_hl[j] & 0xf));
  534.       cpnt = pnt[j] + indx1;
  535.       if(indx1 == indx2){
  536.         *cpnt |= (mask1 & mask2);
  537.       } else {
  538.         *cpnt++ |= mask1;
  539.         k = indx1+1;
  540.         while (k != indx2) {
  541.           *cpnt++ = 0xffffU; 
  542.           k++;
  543.         };
  544.         *cpnt |= mask2;
  545.       };
  546.       ymin_hl[j]=0x7fff; 
  547.       ymax_hl[j]=0;
  548.     };
  549.     };
  550.   };
  551.   free(nodes);
  552.   free(boxlist);
  553.   free(plot_info);
  554. }
  555.  
  556.